﻿using Cysharp.Threading.Tasks;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.EventSystems;

public class UIManager : GameFrameClassBase
{
    public static Canvas canvas, worldCanvas;

    private static Dictionary<string, UIPanelBase> s_CachedPanels = new Dictionary<string, UIPanelBase>();
    private static List<string> s_LoadingPanels = new List<string>();
    private static List<Transform> s_Roots = new List<Transform>();

    public override List<Type> dependences => new List<Type> { typeof(InputManager) };

    public override async UniTask InitAsync()
    {
        //canvas = GameObject.FindObjectsOfTypeAll<Canvas>();
        canvas = GameObject.Find("Canvas").GetComponent<Canvas>();
        worldCanvas = GameObject.Find("WorldCanvas").GetComponent<Canvas>();

        GameObject.DontDestroyOnLoad(canvas);
        GameObject.DontDestroyOnLoad(worldCanvas);

        var types = Enum.GetValues(typeof(UIPanelType));
        foreach (UIPanelType type in types)
        {
            s_Roots.Add(CreateRoot(type.ToString()));
        }
        Transform CreateRoot(string rootName)
        {
            GameObject go = new GameObject(rootName);
            RectTransform rect = go.AddComponent<RectTransform>();
            rect.SetParent(canvas.transform);
            rect.SetAsLastSibling();
            rect.Stretch();
            return rect;
        }

        var eventSystem = GameObject.FindObjectOfType<EventSystem>();
        GameObject.DontDestroyOnLoad(eventSystem);

        var preloadUIs = Tools.GetSubClassesOf<UIPanelBase>();
        foreach (var type in preloadUIs)
        {
            await LoadAsync(type.Name);
        }
    }

    /// <summary>
    /// 异步加载界面
    /// </summary>
    private static async UniTask<UIPanelBase> LoadAsync(string uiName)
    {
        var uiBase = Find(uiName);
        // 已缓存，则直接取出（保护用，一般不进入此状态）
        if (uiBase != null)
        {
            Debug.Log($"UIManager 界面资源加载失败：{uiName} 资源已实例化请勿重复加载");
            return uiBase;
        }

        // 正在加载，则等待其加载完毕，再直接从缓存中读取（保护用，一般不进入此状态）
        if (s_LoadingPanels.Contains(uiName))
        {
            Debug.LogWarning($"UIManager 界面资源加载失败：{uiName} 资源正在加载请勿重复操作");
            await UniTask.WaitUntil(() => !s_LoadingPanels.Contains(uiName));
            return s_CachedPanels[uiName];
        }

        // 未缓存，则加入缓存列表，等待缓存结束后取出
        s_LoadingPanels.Add(uiName);
        var go = await Addressables.InstantiateAsync($"UIs/{uiName}.prefab").Task;
        if (go == null)
        {
            Debug.LogError($"UIManager 界面资源加载失败：{uiName} 资源不存在");
            s_LoadingPanels.Remove(uiName);
            return null;
        }

        uiBase = go.GetComponent<UIPanelBase>();
        if (uiBase == null)
        {
            Addressables.Release(go);
            Debug.LogError($"UIManager 界面资源加载失败：{uiName} 预制体中未找到对应脚本");
            s_LoadingPanels.Remove(uiName);
            return null;
        }

        var root = s_Roots[(int)uiBase.type];
        go.name = uiName;
        go.transform.SetParent(root);
        go.SetActive(false);
        s_CachedPanels[uiName] = uiBase;
        s_LoadingPanels.Remove(uiName);
        Debug.Log($"UIManager 界面加载成功：{uiName}");
        uiBase.Init();
        uiBase.FocusOn();
        return uiBase;
    }

    /// <summary>
    /// 查找界面
    /// </summary>
    public static T Find<T>() where T : UIPanelBase
    {
        return Find(typeof(T).Name) as T;
    }

    /// <summary>
    /// 在界面缓存中查找界面
    /// </summary>
    public static UIPanelBase Find(string uiName)
    {
        s_CachedPanels.TryGetValue(uiName, out var uiBase);
        return uiBase;
    }
}